/****************************************************
	文件：MultiwayTree.cs
	作者：林文豪
	日期：2021/03/21 22:14:38
	功能：1、在构造函数中根据 Goal 和 Actions 创建一颗多叉树
         2、对外公开寻找指定 Action 的方法和寻找所有叶子结点的方法
*****************************************************/
using System;
using System.Collections.Generic;
using System.Linq;

namespace MyGame.AI.GOAP {
	public class MultiwayTree {
		private Queue<MultiwayTreeNode> _TempQueue;    // 采用层序遍历的方式初始化多叉树
		private List<MultiwayTreeNode>  _LeafNodes;    // 叶子节点
		private List<IAction>           _UsingActions; // 为了到达指定的Goal，所有使用到的Actions

		public List<IAction>          UsingActions => _UsingActions;
		public List<MultiwayTreeNode> LeafNodes    => _LeafNodes;

		public MultiwayTree(IGoal head, List<IAction> actions) {
			_TempQueue    = new Queue<MultiwayTreeNode>();
			_LeafNodes    = new List<MultiwayTreeNode>();
			_UsingActions = new List<IAction>();
			CreateTree(head, actions);
		}

		public List<MultiwayTreeNode> GetNodesToGoal(MultiwayTreeNode node) {
			_UsingActions.Clear();
			List<MultiwayTreeNode> result   = new List<MultiwayTreeNode>();
			MultiwayTreeNode       tempNode = node;
			while (tempNode.Parent != null) {
				result.Add(tempNode);

				if (tempNode.Content is IAction action) {
					if (_UsingActions.Contains(action) == false) {
						_UsingActions.Add(action);
					}
				}

				tempNode = tempNode.Parent;
			}

			result.Add(tempNode);
			return result;
		}

		public List<List<MultiwayTreeNode>> GetAllLeafToGoalRound() {
			List<List<MultiwayTreeNode>> result = new List<List<MultiwayTreeNode>>();
			foreach (MultiwayTreeNode leafNode in _LeafNodes) {
				result.Add(GetNodesToGoal(leafNode));
			}
			return result;
		}

		private void CreateTree(IGoal head, List<IAction> actions) {
			bool hasFindEff;
			_TempQueue.Enqueue(new MultiwayTreeNode(null, head)); // 装入头节点
			while (_TempQueue.Count > 0) {
				MultiwayTreeNode treeNode = _TempQueue.Dequeue(); // 从队列中取出第一个元素
				hasFindEff = false;
				if (treeNode.Content.GetPreconditions() != null) {
					for (int i = 0; i < actions.Count; i++) {
						if (treeNode.Content.GetPreconditions().CanLink(actions[i].GetEffects())) {
							if (CheckIsCircle(treeNode, actions[i]) == false) {
								MultiwayTreeNode node = new MultiwayTreeNode(treeNode, actions[i]);
								_TempQueue.Enqueue(node);
								hasFindEff = true;
							}
						}
					}
				}
				else {
					foreach (IAction action in actions) {
						if (CheckIsCircle(treeNode, action) == false) {
							MultiwayTreeNode node = new MultiwayTreeNode(treeNode, action);
							_TempQueue.Enqueue(node);
							hasFindEff = true;
						}
					}
				}
				if (hasFindEff == false) {
					_LeafNodes.Add(treeNode);
				}
			}
		}

		public RoundToGoal GetRoundToGoal(MultiwayTreeNode node) {
			return new RoundToGoal(node);
		}

		private bool CheckIsCircle(MultiwayTreeNode targetNode, INode content) {
			// 不能出现环路
			MultiwayTreeNode tempNode = targetNode;
			while (tempNode.Parent != null) {
				if (tempNode.Content == content) {
					return true;
				}
				tempNode = tempNode.Parent;
			}

			return false;
		}
	}
}
